<template>
    <div class="w-full">
        <el-upload ref="uploadRef" :accept="accept" v-model:file-list="fileList" class="w-full" :auto-upload="false"
            :limit="limit" :multiple="multiple" :on-change="handleChange" :list-type="listType"
            :on-remove="handleRemove" :on-exceed="handleExceed" :on-preview="handlePictureCardPreview"
            :before-remove="beforeRemove">
            <slot name="button">
                <el-button class="w-full">
                    <el-icon>
                        <Plus class="fs-14" />
                    </el-icon>
                    添加附件
                </el-button>
            </slot>
            <!-- <template #file="{ file }">
                <div>
                    <img class="el-upload-list__item-thumbnail" crossorigin="anonymous" :src="file.url" alt="" />
                    <span class="el-upload-list__item-actions">
                        <span class="el-upload-list__item-delete" @click="handleRemove(file)">
                            <el-icon>
                                <Delete />
                            </el-icon>
                        </span>
                    </span>
                </div>
            </template> -->
        </el-upload>
    </div>
    <Teleport to="body">
        <div v-if="dialogVisible" class="shadow-box">
            <!-- <div class="close pointer" @click="dialogVisible = false">
                <el-icon>
                    <CloseBold />
                </el-icon>
            </div> -->
            <div class="img-box">
                <el-image ref="imgRef" class="img" :initial-index="initIndex" crossorigin="anonymous"
                    :src="dialogImageUrl" :preview-src-list="previews" fit="cover" @close="handleClose" />
            </div>
        </div>
    </Teleport>
</template>
<script setup>
import { ref, watch } from 'vue'
import { ElMessage, genFileId, ElMessageBox } from 'element-plus'
import * as imageConversion from 'image-conversion'

const fileList = ref([])
const uploadRef = ref(null)
const dialogImageUrl = ref('')
const dialogVisible = ref(false)

const props = defineProps({
    accept: {
        type: String,
        default: '.jpg,.jpeg,.png,.gif,.JPG,.JPEG,.PNG,.GIF'
    },
    base64File: {
        type: [String, Array]
    },
    fileUrl: {
        type: [String, Array]
    },
    limit: {
        type: [Number, String],
        default: 1
    },
    multiple: {
        type: Boolean,
        default: false
    },
    listType: {
        type: String,
        default: 'picture-card'
    },
    limitSize: {
        type: Number,
        limit: 2
    },
    exceed: {
        type: Boolean,
        default: false
    },
    canCompress: {
        type: Boolean,
        default: false
    },
    propName: {
        type: String,
        default: ''
    },
    removeConfirm: {
        type: Boolean,
        default: false
    },
    previewList: {
        type: Array,
        default() {
            return []
        }
    }
})

const previews = ref([])

const imgRef = ref(null)

const initIndex = ref(0)

const emits = defineEmits(['update:base64File', 'success', 'remove'])

const handleChange = async (file) => {
    let rawFile = file.raw
    if (!rawFile) return
    const typeList = props.accept.split(',')
    const fileType = rawFile.name.substring(rawFile.name.lastIndexOf('.'))
    if (typeList.every(i => i !== fileType)) {
        ElMessage.error('只能上传格式为图片的文件')
        fileList.value = []
        return false
    } else if (rawFile.size / 1024 / 1024 > props.limitSize) {
        if (props.canCompress) {
            rawFile = await imageConversion.compressAccurately(rawFile, (props.limitSize - 1) * 1024)
        } else {
            ElMessage.error(`只能上传大小为${props.limitSize}M以内的图片`)
            fileList.value = []
            return false
        }
    }
    const imgFile = new FileReader()
    imgFile.readAsDataURL(rawFile)
    imgFile.onload = res => {
        const base64 = res.target.result.split('base64,')[1]
        rawFile.base64 = base64
        if (Array.isArray(props.fileUrl)) {
            // emits('update:base64File', [...props.base64File, base64])
            emits('success', base64)
        } else {
            emits('update:base64File', base64)
        }
        // fileList.value = []
    }
    return true
}

const beforeRemove = () => {
    if (props.removeConfirm) {
        return ElMessageBox.confirm(
            '是否删除该材料？',
            '提示',
            {
                confirmButtonText: '确定',
                cancelButtonText: '取消',
                type: 'warning',
            }
        )
            .then(
                () => true,
                () => false
            )
    } else {
        return () => true
    }
}

const handleRemove = (file) => {
    // const list = fileList.value.map(i => {
    //     return i.raw.base64
    // })
    if (Array.isArray(props.fileUrl)) {
        // emits('update:base64File', list)
        emits('remove', file)
    } else {
        emits('update:base64File', '')
    }
}

const handleExceed = (files) => {
    if (props.exceed) {
        uploadRef.value.clearFiles()
        const file = files[0]
        file.uid = genFileId()
        uploadRef.value.handleStart(file)
    } else {
        ElMessage.error({
            message: `最多只能上传${props.limit}张`
        })
    }
}

const handlePictureCardPreview = (uploadFile) => {
    dialogImageUrl.value = uploadFile.url
    dialogVisible.value = true
    setTimeout(() => {
        const cur = imgRef.value.src
        initIndex.value = props.previewList.findIndex(i => i === cur)
        const dom = imgRef.value.$refs.container.children[0]
        // dom.style.opacity = 0
        dom.click()
        // imgRef.value.$refs.container.click()
    }, 100)
}

const handleClose = () => {
    dialogVisible.value = false
}

function getBase64Image(img) {
    const canvas = document.createElement('canvas')
    canvas.width = img.width
    canvas.height = img.height
    const ctx = canvas.getContext('2d')
    ctx.drawImage(img, 0, 0, canvas.width, canvas.height)
    const dataURL = canvas.toDataURL()
    return dataURL
}

const createFile = (url) => {
    const image = new Image()
    let newUrl = url
    if (props.propName) {
        newUrl = url[props.propName]
    }
    image.src = newUrl + '?v=' + Math.random()
    image.crossOrigin = 'anonymous'
    image.onload = function () {
        const fullbase64 = getBase64Image(image)
        const base64 = fullbase64.split('base64,')[1]
        if (Array.isArray(props.base64File)) {
            // emits('update:base64File', [{
            //     ...url,
            //     base64
            // }])
        } else {
            emits('update:base64File', base64)
        }
    }
    if (typeof url === 'string') {
        fileList.value.push({
            url: newUrl,
            uid: url?.fileId ?? genFileId()
        })
    } else {
        fileList.value.push({
            ...url,
            url: newUrl,
            uid: url?.fileId ?? genFileId()
        })
    }
}

const clearFiles = () => {
    uploadRef.value?.clearFiles()
}

// 将后端传过来的图片url转成base64
watch(() => props.fileUrl, (newval) => {
    if (!newval) {
        fileList.value = []
    } else {
        if (!Array.isArray(newval)) {
            createFile(newval)
        }
        if (Array.isArray(newval)) {
            fileList.value = []
            newval.forEach(i => {
                createFile(i)
            })
        }
    }
}, {
    immediate: true,
})

watch(() => props.previewList, (newval) => {
    previews.value = newval || []
}, {
    immediate: true
})


defineExpose({
    clearFiles
})

</script>
<style lang="scss" scoped>
:deep(.el-upload) {
    width: 100%;
}

:deep(.el-button) {
    border-style: dashed;
}

:deep(.el-upload--picture-card) {
    height: 32px !important;
    border: none;
}

:deep(.w-full .el-upload-list--picture-card) {
    width: 100% !important;
}

:deep(.w-full .el-upload--picture-card) {
    width: 100% !important;
}

.shadow-box {
    position: fixed;
    left: 0;
    top: 0;
    width: 100vw;
    height: 100vh;
    background: rgba(0, 0, 0, 0.5);
    z-index: 10086;
}

.close {
    position: absolute;
    right: 20px;
    top: 20px;
    font-size: 40px;
    color: #fff;
}

.img-box {
    // position: absolute;
    // left: 50%;
    // top: 50%;
    // transform: translate(-50%, -50%);
    // width: auto;
    // max-height: 70vw;
}

.img {
    // opacity: 0;
}

:deep().el-upload-list__item.is-success:focus:not(:hover) .el-icon--close-tip {
    display: none;
}

:deep().el-image__preview {
    opacity: 0;
    visibility: hidden;
}
</style>